package com.modular.iot.opt;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import com.c.opt.ComOpt;
import com.ToolOpt;
import com.modular.iot.bean.ThingsAttributeDo;
import com.modular.iot.bo.IotAttribute;
import com.modular.iot.tool.ToolIotCmd;
import ntd.util.ToolLock;
import ntd.util.config.common.exception.ComException;
import ntd.util.frame.action.iot.bo.SmartEmissionAgreementBo;
import ntd.util.frame.action.iot.cache.SmartEmissionAgreementCache;
import ntd.util.frame.action.iot.context.IotContext;
import ntd.util.modular.data.util.handle.tool.Tool212;
import ntd.util.modular.things.entity.Device;

import java.util.Date;
import java.util.List;

public class OptIotAttribute extends ComOpt<ThingsAttributeDo> {

    public OptIotAttribute() {
        super("things_attribute");
    }

    /**
     * 保存或更新配置信息
     * @param iotAttribute
     */
    public void syncAttribute(IotAttribute iotAttribute) {
        ThingsAttributeDo thingsAttributeDo = query().eq("device_id", iotAttribute.getDeviceId())
                .eq("product_id", iotAttribute.getProductId())
                .eq("code", Opt.ofBlankAble(iotAttribute.getCode()).orElseThrow(() -> new ComException("属性code不能为空...")))
                .eq("is_shadow", "2")
                .getBean();
        if (ObjectUtil.isNotNull(thingsAttributeDo)) {
            iotAttribute.setId(thingsAttributeDo.getId());
        }
        syncBean(iotAttribute);
    }

    /**
     * 查询设备属性列表
     * @param deviceCode
     * @return
     */
    public List<ThingsAttributeDo> list(String deviceCode) {
        Device device = ToolOpt.OPT_T_DEVICE.getByCode(Opt.ofBlankAble(deviceCode).orElseThrow(() -> new ComException("设备code不能为空...")));
        String deviceId = Opt.ofNullable(device).orElseThrow(() -> new ComException("找不到设备[{}]信息...", deviceCode)).getId();
        return query().eq("device_id", deviceId).eq("is_shadow", "2").listBean();
    }

    /**
     * 获取产品属性
     * @param productId 产品id
     * @param attributeCode 属性编码
     * @return
     */
    public ThingsAttributeDo getProductThingsAttributeDo(String productId, String attributeCode) {
        return Opt.ofNullable(query().eq("product_id", productId).eq("is_shadow", "2")
                .eq("code", Opt.ofBlankAble(attributeCode).orElseThrow(() -> new ComException("属性code不能为空...")))
                .getBean()).orElseThrow(() -> new ComException("该产品[{}]找不到属性[{}]...", productId, attributeCode));
    }

    /**
     * 获取设备属性信息 - 找不到就获取产品属性信息
     * @param deviceCode 设备编码
     * @param attributeCode 属性编码
     * @return
     */
    public ThingsAttributeDo getDeviceThingsAttributeBo(String deviceCode, String attributeCode) {
        if (StrUtil.isBlank(attributeCode)) {
            throw new ComException("属性code不能为空...");
        }
        if (StrUtil.isBlank(deviceCode)) {
            throw new ComException("设备code不能为空...");
        }
        // 获取设备信息
        Device device = ToolOpt.OPT_T_DEVICE.getByCode(deviceCode);
        // 更新设备状态
        ThingsAttributeDo thingsAttributeDo = query().eq("device_id", device.getId())
                .eq("is_shadow", "2")
                .eq("code", attributeCode)
                .getBean();
        if (ObjectUtil.isNull(thingsAttributeDo)) {
            // 获取设备属性失败 - 获取产品属性并清理产品特异属性
            thingsAttributeDo = getProductThingsAttributeDo(device.getProductId(), attributeCode);
            thingsAttributeDo.setId(null);
            thingsAttributeDo.setProductId(null);
            thingsAttributeDo.setDeviceId(device.getId());
            return thingsAttributeDo;
        }
        return thingsAttributeDo;
    }

    /**
     * 获取设备未执行完成属性信息
     * @param deviceCode
     * @param attributeCode
     * @return
     */
    public ThingsAttributeDo getUnExeThingsAttributeBo(String deviceCode, String attributeCode) {
        // 反馈状态执行
        Device device = ToolOpt.OPT_T_DEVICE.getByCode(Opt.ofBlankAble(deviceCode).orElseThrow(() -> new ComException("设备code不能为空...")));
        return query().eq("device_id", device.getId()).eq("is_final", "0").eq("is_shadow", "1")
                .eq("code", Opt.ofBlankAble(attributeCode).orElseThrow(() -> new ComException("属性code不能为空..."))).getBean();
    }

    /**
     * 更新设备属性 - 手动操作
     * @param deviceCode
     * @param attributeCode
     * @param val
     */
    public void updateDeviceAttribute(String deviceCode, String attributeCode, String val) {
        Device device = ToolOpt.OPT_T_DEVICE.getByCode(Opt.ofBlankAble(deviceCode).orElseThrow(() -> new ComException("设备code不能为空...")));
        String deviceId = Opt.ofNullable(device).orElseThrow(() -> new ComException("找不到设备[{}]信息...", deviceCode)).getId();

        // 2. 验证当前状态 - 如果等于要修改的状态则直接返回
        ThingsAttributeDo thingsAttributeDo = getDeviceThingsAttributeBo(deviceCode, attributeCode);
//        if (ObjectUtil.isNotNull(thingsAttributeDo.getId()) && thingsAttributeDo.getVal().equals(val)) {
//            return;
//        }

        ToolLock.lockRun("updateDeviceAttribute" + deviceCode + attributeCode, () -> {
            // 准备操作信息保存
            // 1. 验证是否存在未执行操作
//            ThingsAttributeDo unExeThingsAttributeBo = getUnExeThingsAttributeBo(deviceCode, attributeCode);
//            if (ObjectUtil.isNotNull(unExeThingsAttributeBo)) {
//                throw new ComException("存在未执行操作,请等待执行完成!");
//            }

            // 2. 存入待执行操作
            thingsAttributeDo.setId(null);
            thingsAttributeDo.setProductId(null);
            thingsAttributeDo.setDeviceId(deviceId);
            thingsAttributeDo.setIsShadow(1);
            thingsAttributeDo.setIsFinal(0);
            thingsAttributeDo.setVal(val);
            thingsAttributeDo.setCreatedBy(null);
            thingsAttributeDo.setCreatedDate(null);
            syncBean(thingsAttributeDo);

            // 3. 调用执行操作
            handle(thingsAttributeDo, deviceCode);
        });
    }

    /**
     * 反馈状态执行
     * @param deviceCode 设备编码
     * @param code 操作编码
     * @param val 操作值
     */
    public void exeFinal(String deviceCode, String code, String val) {
        if (StrUtil.isBlank(code)) {
            throw new ComException("设备属性code不能为空...");
        }
        if (StrUtil.isBlank(val)) {
            throw new ComException("设备属性值不能为空...");
        }
        if (StrUtil.isBlank(deviceCode)) {
            throw new ComException("设备编码不能为空...");
        }

        ToolLock.lockRun("exeFinal" + deviceCode + code, () -> {
            // 更新设备状态
            ThingsAttributeDo thingsAttributeDo = getDeviceThingsAttributeBo(deviceCode, code);
            thingsAttributeDo.setVal(val);
            thingsAttributeDo.setIsFinal(1);
            syncBean(thingsAttributeDo);
            StaticLog.info("LJ_更新设备[{}]属性[{}]成功[{}]...", deviceCode, code, val);

            // 更新上次执行指令状态
//            ThingsAttributeDo unExeThingsAttributeBo = getUnExeThingsAttributeBo(deviceCode, code);
//
//            if (ObjectUtil.isNotNull(unExeThingsAttributeBo)) {
//                // 如果状态变更成功
//                if (unExeThingsAttributeBo.getVal().equals(val)) {
//                    unExeThingsAttributeBo.setIsFinal(1);
//                    syncBean(unExeThingsAttributeBo);
//                } else {
//                    // 判断超过3分钟执行未成功则标记为失败
//                    Date createdDate = unExeThingsAttributeBo.getCreatedDate();
//                    if (DateUtil.compare(DateUtil.offsetMinute(createdDate, 3), DateUtil.date()) < 0) {
//                        unExeThingsAttributeBo.setIsFinal(2);
//                        syncBean(unExeThingsAttributeBo);
//                    }
//                }
//            }
        });
    }

    /**
     * 执行具体远程操作
     * @param thingsAttributeDo
     * @param deviceCode
     */
    private void handle(ThingsAttributeDo thingsAttributeDo, String deviceCode) {
        String code = thingsAttributeDo.getCode();
        switch (code) {
            // 排污阀操作
            case "blowdown_valve": {
                handleFmkz(IotContext.init(deviceCode), "0", BooleanUtil.toBoolean(thingsAttributeDo.getVal()));
                break;
            }
            // 应急阀操作
            case "emergency_valve": {
                handleFmkz(IotContext.init(deviceCode), "1", BooleanUtil.toBoolean(thingsAttributeDo.getVal()));
                break;
            }
            // 无需特殊操作的直接更新属性值信息
            default: {
                exeFinal(deviceCode, code, thingsAttributeDo.getVal());
            }
        }
    }

    /**
     * 阀门控制执行
     * @param iotContext
     * @return true 代表执行完成
     */
    private void handleFmkz(IotContext iotContext, String fmNum, boolean fmAction) {
        SmartEmissionAgreementBo smartEmissionAgreementBo = SmartEmissionAgreementCache.get(iotContext.getDeviceCode());

        if (StrUtil.isNotBlank(fmNum)) {
            if (smartEmissionAgreementBo.isAutoRun()) {
                throw new ComException("请先调整设备为手动控制再进行对应操作...");
            }

            if ("0".equals(fmNum)) {
                // 判断如果当前状态是已变更，则直接返回成功
//                if (smartEmissionAgreementBo.isValve() == fmAction) {
//                    exeFinal(iotContext.getDeviceCode(), "blowdown_valve", StrUtil.toString(fmAction));
//                    return;
//                }
                smartEmissionAgreementBo.setValve(fmAction);
            }
            if ("1".equals(fmNum)) {
                // 如果当前状态是已变更，则直接返回成功
//                if (smartEmissionAgreementBo.isValve2() == fmAction) {
//                    exeFinal(iotContext.getDeviceCode(), "emergency_valve", StrUtil.toString(fmAction));
//                    return;
//                }
                smartEmissionAgreementBo.setValve2(fmAction);
            }

            // 执行规则
            ToolIotCmd.pushCmd(iotContext.getDeviceCode(), Tool212.build212Bo(iotContext.getDeviceCode(), smartEmissionAgreementBo).to212Str(),
                ToolIotCmd.TYPE_212, "手动控制");
        }
    }

}
